package pack3_abstractFactory;
import java.lang.reflect.Constructor;

//Human接口：方便在工厂中使用约束泛型 <T extends Human>，接口本质仍然是个类，可以继承
interface Human{
    void getColor();
    void getSex();
}

//Human抽象类：方便在工厂中使用约束泛型 <T extends Human>
// abstract class Human{
//     void getColor(){};
//     void getSex(){};
// }

//抽象类：不能实例化, 不用实现所有接口方法
abstract class AbstractBlackHuman implements Human{
    public void getColor(){
        System.out.println("I am a black human");
    }
}

abstract class AbstractWhiteHuman implements Human{
    public void getColor(){
        System.out.println("I am a white human");
    }
}

abstract class AbstractYellowHuman implements Human{
    public void getColor(){
        System.out.println("I am a yellow human");
    }
}

//人种实现类
class MaleBlackHuman extends AbstractBlackHuman{
    @Override
    public void getSex() {
        super.getColor();
        System.out.println("I am a boy");
    }
}

class FemaleBlackHuman extends AbstractBlackHuman{
    @Override
    public void getSex() {
        super.getColor();
        System.out.println("I am a girl");
    }
}

class MaleWhiteHuman extends AbstractWhiteHuman{
    @Override
    public void getSex() {
        super.getColor();
        System.out.println("I am a boy");
    }
}

class FemaleWhiteHuman extends AbstractWhiteHuman{
    @Override
    public void getSex() {
        super.getColor();
        System.out.println("I am a girl");
    }
}

class MaleYellowHuman extends AbstractYellowHuman{
    @Override
    public void getSex() {
        super.getColor();
        System.out.println("I am a boy");
    }
}

class FemaleYellowHuman extends AbstractYellowHuman{
    @Override
    public void getSex() {
        super.getColor();
        System.out.println("I am a girl");
    }
}

/**
 * 一定要理清楚抽象工厂和子类工厂分别要做哪些任务：
 * 1）抽象工厂：定义行为，无需实例化human对象（抽象工厂用 抽象类 或者 接口 来声明都行，两者可相互替代（继承抽象类时子类需要重写所有抽象方法））
 * 2）子类工厂：实现指定行为，需要实例化指定human对象
 * Note：
 *   1）先有男女，再有黑黄白人种；
 *   2）先有windows、linux，再有chrome，edge等浏览器；
 *   3）先者为子类工厂；再者为抽象工厂
 * 一下注释部分为错误演示
 */
//抽象工厂（×）：用于生产不同人种，但不能实例化
// abstract class abstractFactory{

//     //这里只允许其子类工厂调用，因此不设置为static
//     public <T extends Human> T createHuman(Class<T> human_clz){

//         T human = null;
//         try{
//             //构造不同人种
//             Constructor constructor = Class.forName(human_clz.getName()).getDeclaredConstructor();
//             human = (T) constructor.newInstance();

//         }catch(Exception e){
//             e.printStackTrace();
//         }
//         return human;
//     }
// }
//实现工厂（×）: 用于生产不同性别
// class YellowHumanFactory extends abstractFactory{
//     public <T extends AbstractYellowHuman> T createYellowHuman(Class<T> yellowHuman_clz){

//         T yellowHuman = null;
//         try{
//             //构造不同性别
//             Constructor constructor = Class.forName(yellowHuman_clz.getName()).getDeclaredConstructor();
//             constructor.newInstance();
//         }catch(Exception e){
//             e.printStackTrace();
//         }
//         return yellowHuman;
//     } 
// }

//抽象工厂：将人种实例化过程交给子类工厂去实现
abstract class abstractFactory{
    //这里只允许其子类工厂调用，因此不设置为static
    public abstract <T extends AbstractYellowHuman> T createYellowHuman(Class<T> human_clz);
    public abstract <T extends AbstractWhiteHuman> T createWhiteHuman(Class<T> human_clz);
    public abstract <T extends AbstractBlackHuman> T createBlackHuman(Class<T> human_clz);
}

//子类工厂：将人种实例化过程交给子类工厂去实现，子类工厂包括
class FemaleHumanFactory extends abstractFactory{

    @Override
    public <T extends AbstractYellowHuman> T createYellowHuman(Class<T> human_clz) {
        T human = null;
        try{
            //构造不同人种
            Constructor constructor = Class.forName(human_clz.getName()).getDeclaredConstructor();
            human = (T) constructor.newInstance();

        }catch(Exception e){
            e.printStackTrace();
        }
        return human;
    }

    @Override
    public <T extends AbstractWhiteHuman> T createWhiteHuman(Class<T> human_clz) {
        T human = null;
        try{
            //构造不同人种
            Constructor constructor = Class.forName(human_clz.getName()).getDeclaredConstructor();
            human = (T) constructor.newInstance();

        }catch(Exception e){
            e.printStackTrace();
        }
        return human;
    }

    @Override
    public <T extends AbstractBlackHuman> T createBlackHuman(Class<T> human_clz) {
        T human = null;
        try{
            //构造不同人种
            Constructor constructor = Class.forName(human_clz.getName()).getDeclaredConstructor();
            human = (T) constructor.newInstance();

        }catch(Exception e){
            e.printStackTrace();
        }
        return human;
    }
    
}

class MaleHumanFactory extends abstractFactory{

    @Override
    public <T extends AbstractYellowHuman> T createYellowHuman(Class<T> human_clz) {
        T human = null;
        try{
            //构造不同人种
            Constructor constructor = Class.forName(human_clz.getName()).getDeclaredConstructor();
            human = (T) constructor.newInstance();

        }catch(Exception e){
            e.printStackTrace();
        }
        return human;
    }

    @Override
    public <T extends AbstractWhiteHuman> T createWhiteHuman(Class<T> human_clz) {
        T human = null;
        try{
            //构造不同人种
            Constructor constructor = Class.forName(human_clz.getName()).getDeclaredConstructor();
            human = (T) constructor.newInstance();

        }catch(Exception e){
            e.printStackTrace();
        }
        return human;
    }

    @Override
    public <T extends AbstractBlackHuman> T createBlackHuman(Class<T> human_clz) {
        T human = null;
        try{
            //构造不同人种
            Constructor constructor = Class.forName(human_clz.getName()).getDeclaredConstructor();
            human = (T) constructor.newInstance();

        }catch(Exception e){
            e.printStackTrace();
        }
        return human;
    }
}

public class code001_abstractFactory{
    public static void main(String[] args) {

        FemaleHumanFactory fHumanFactory = new FemaleHumanFactory();
        MaleHumanFactory mHumanFactory = new MaleHumanFactory();

        //创建小黄人
        Human h1 = fHumanFactory.createYellowHuman(FemaleYellowHuman.class);
        Human h2 = mHumanFactory.createYellowHuman(MaleYellowHuman.class);
        h1.getSex();
        h2.getSex();

        //创建小黑人
        Human h3 = fHumanFactory.createBlackHuman(FemaleBlackHuman.class);
        Human h4 = mHumanFactory.createBlackHuman(MaleBlackHuman.class);
        h3.getSex();
        h4.getSex();

        //创建小白人
        Human h5 = fHumanFactory.createWhiteHuman(FemaleWhiteHuman.class);
        Human h6 = mHumanFactory.createWhiteHuman(MaleWhiteHuman.class);
        h5.getSex();
        h6.getSex();
    }
}
